package run.microservice.stock.utils;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import lombok.extern.slf4j.Slf4j;
import run.microservice.stock.serializer.DictSerializerModifier;

import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * JSON工具类
 * @author lunfangyu
 */
@Slf4j
public class ObjectMapperUtil {

    public static final String PATTERN_DATETIME = "yyyy-MM-dd HH:mm:ss";
    private static final ObjectMapper MAPPER = new ObjectMapper();

    static {
        // 允许key有单引号
        MAPPER.enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES);
        // 允许key没有双引号
        MAPPER.enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES);
        //将浮点小数转为BigDecimal
        MAPPER.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
        //配置为true表示mapper接受只有一个元素的数组的反序列化
        MAPPER.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
        //反序列化如果碰到不识别的枚举值，是否作为空值解释，true\enable:不会抛不识别的异常, 会赋空值；false\disable:会抛不识别的异常
        MAPPER.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL);

        //忽略空Bean转json的错误
        MAPPER.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        //取消默认转换timestamps形式
        MAPPER.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        //忽略 在json字符串中存在，但是在java对象中不存在对应属性的情况。防止错误
        MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

        //对象的所有字段全部列入
        MAPPER.setSerializationInclusion(JsonInclude.Include.ALWAYS);
        //所有的日期格式都统一为以下的样式，即yyyy-MM-dd HH:mm:ss
        MAPPER.setDateFormat(new SimpleDateFormat(PATTERN_DATETIME));
        //反序列化时智能识别变量名（识别没有按驼峰格式命名的变量名）
        MAPPER.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);

        // 解决Long、BigInt精度丢失问题，BigDecimal科学计数问题
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        simpleModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);
        simpleModule.addSerializer(BigInteger.class, ToStringSerializer.instance);

        // 日期和时间格式化; 注意，使用JavaTimeModule进行时间格式配置会不生效
        simpleModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE));
        simpleModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ISO_LOCAL_TIME));
        simpleModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
        simpleModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ISO_LOCAL_DATE));
        simpleModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ISO_LOCAL_TIME));
        simpleModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ISO_LOCAL_DATE_TIME));

        // 设置字典序列化修改类
        simpleModule.setSerializerModifier(new DictSerializerModifier());

        MAPPER.registerModule(simpleModule);
    }

    private ObjectMapperUtil() {}
    /** 静态内部类单例模式 */
    private static class SingletonHolder {
        private static final ObjectMapperUtil INSTANCE = new ObjectMapperUtil();
    }
    /** 防止序列化破坏单例 */
    protected Object readResolve() {
        return ObjectMapperUtil.SingletonHolder.INSTANCE;
    }
    /** 获取实例的方法 */
    public static ObjectMapperUtil getInstance() {
        return ObjectMapperUtil.SingletonHolder.INSTANCE;
    }

    /**
     * 获取 ObjectMapper 实例
     * @return ObjectMapper
     */
    public ObjectMapper getObjectMapper() {
        return MAPPER;
    }

    /**
     * 创建ObjectNode
     * @return ObjectNode
     */
    public ObjectNode createObjectNode() {
        return MAPPER.createObjectNode();
    }

    /**
     * 创建ArrayNode
     * @return ArrayNode
     */
    public ArrayNode createArrayNode() {
        return MAPPER.createArrayNode();
    }

    /**
     * 将集合类或者JavaBean序列化为JSON字符串
     * @param obj Java对象（如 POJO、List、Map、Set 等）
     * @return JSONString
     */
    public String toJSONString(Object obj) {
        return toJsonStr(obj, false);
    }

    /**
     * 将集合类或者JavaBean序列化为带格式的JSON字符串
     * @param obj Java对象（如 POJO、List、Map、Set 等）
     * @return String
     */
    public String toJsonStrFormat(Object obj) {
        return toJsonStr(obj, true);
    }

    /**
     * 将JSON字符串解析为JsonNode
     * @param jsonStr Json字符串
     * @return JsonNode
     */
    public JsonNode parse(String jsonStr) {
        if (isEmpty(jsonStr)) {
            return null;
        }

        try {
            return MAPPER.readTree(jsonStr);
        } catch (JsonProcessingException e) {
            log.error(String.format("JSON解析异常: %s", jsonStr), e);
        }
        return null;
    }

    /**
     * 把JSON字符串转换成集合类或者JavaBean
     * @param jsonStr Json字符串
     * @param targetClazz 对象类型
     * @return T JavaBean对象（如 POJO、DTO、BO等）
     */
    public final <T> T parseObject(String jsonStr, Class<T> targetClazz) {
        if (isExistEmpty(jsonStr, targetClazz)) {
            return null;
        }

        try {
            return MAPPER.readValue(jsonStr, targetClazz);
        } catch (JsonProcessingException e) {
            log.error(String.format("JSON解析异常: clazz=%s; jsonStr=%s", targetClazz, jsonStr), e);
        }
        return null;
    }

    /**
     * 把JSON字符串转换成JavaBean集合
     * @param jsonStr  Json字符串
     * @param targetClazz 对象类型
     * @return List<T> Java对象集合（如 List<DTO>、List<POJO> 等）
     */
    public final <T> List<T> parseArray(String jsonStr, Class<T> targetClazz) {
        if (isExistEmpty(jsonStr, targetClazz)) {
            return new ArrayList<>();
        }

        try {
            JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, targetClazz);
            return MAPPER.readValue(jsonStr, javaType);
        } catch (JsonProcessingException e) {
            log.error(String.format("JSON解析异常: clazz=%s; jsonStr=%s", targetClazz, jsonStr), e);
        }
        return new ArrayList<>();
    }

    /**
     * 把JSON字符串转成集合类或者JavaBean, 可转为复杂类型如：List<Object>
     * 把JSON字符串转换成JavaBean
     * @param jsonStr Json字符串
     * @param type 复杂对象类型；例如：TypeReference<List<Object>> type = new TypeReference<>(){};
     * @return T Java对象（如 POJO、DTO、List、Map、Set、List<DTO>、Map<String, POJO>等）
     */
    public final <T> T parseObject(String jsonStr, TypeReference<T> type) {
        if (isExistEmpty(jsonStr, type)) {
            return null;
        }
        try {
            return MAPPER.readValue(jsonStr, type);
        } catch (JsonProcessingException e) {
            log.error(String.format("JSON解析异常: %s", jsonStr), e);
        }
        return null;
    }

    /**
     * Java对象转换(同名属性复制，深拷贝)，更多用于复杂的对象转换，比如POJO转为DTO等
     * @param javaBean 要转换的javaBean；例如 POJO、DTO
     * @param targetClazz 转换目标对象类型, 例如：BO\VO\DTO等
     * @return T JavaBean对象
     */
    public final <T> T convertObject(Object javaBean, Class<T> targetClazz) {
        if (isExistEmpty(javaBean, targetClazz)) {
            return null;
        }
        // treeToValue和convertValue都是用于对象互转，但convertValue侧重于入参是JavaBean, 用于Bean与Bean之间的转换
        return MAPPER.convertValue(javaBean, targetClazz);
    }

    /**
     * Java对象转换(同名属性复制，深拷贝)，更多用于简单的对象转换，比如List<Map<String, JavaBean>>这种复杂对象
     * @param javaObject 源Java对象
     * @param type 转换目标对象类型；例如：TypeReference<List<Object>> type = new TypeReference<>(){};
     * @return T Java对象（如 POJO、List、Map、Set, List<Map<String, JavaBean>>等）
     */
    public final <T> T convertObject(Object javaObject, TypeReference<T> type) {
        if (isExistEmpty(javaObject, type)) {
            return null;
        }
        // treeToValue和convertValue都是用于对象互转，但convertValue侧重于入参是JavaBean, 用于Bean与Bean之间的转换
        return MAPPER.convertValue(javaObject, type);
    }

    /**
     * 把JsonNode转换为Java对象(同名属性复制，深拷贝)，包括JavaBean或者其他复杂的Java对象，比如List<Map<String, JavaBean>>这种复杂对象
     * @param jsonNode ObjectNode
     * @param type 转换目标对象类型；例如：TypeReference<List<Object>> type = new TypeReference<>(){};
     * @return T Java对象（如 POJO、List、Map、Set, List<Map<String, JavaBean>>等）
     */
    public final <T> T convertObject(JsonNode jsonNode, TypeReference<T> type) {
        if (isExistEmpty(jsonNode, type)) {
            return null;
        }

        try {
            // treeToValue和convertValue是对象互转，但treeToValue侧重于入参是JsonNode；而convertValue则为任意对象
            return MAPPER.treeToValue(jsonNode, type);
        } catch (JsonProcessingException e) {
            log.error(String.format("JsonNode转换异常: %s", jsonNode), e);
        }
        return null;
    }

    /**
     * Java对象转换(同名属性复制，深拷贝)，更多用于集合对象转换，比如List<AaDTO>转换为List<AaDO>等
     * @param object 要转换的源对象；例如List<AaDTO>
     * @param targetClazz 转换目标对象类型
     * @return T Java对象（如 POJO、List、Map、Set等）
     */
    public final <T> List<T> convertObjectList(Object object, Class<T> targetClazz) {
        if (isExistEmpty(object, targetClazz)) {
            return null;
        }
        JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, targetClazz);
        return MAPPER.convertValue(object, javaType);
    }

    /**
     * 将JAVA对象转换为JsonNode
     * 如果传入的是String字符串，仍然返回字符串；json字符串转JsonNode应该使用parse方法
     * @param obj Java对象（如 POJO、List、Map、Set 等）
     * @return JsonNode
     */
    public JsonNode toJsonNode(Object obj) {
        if (isEmpty(obj)) {
            return null;
        }
        return MAPPER.valueToTree(obj);
    }

    /**
     * 把JSON字符串转换成ObjectNode
     * @param jsonStr Json字符串
     * @return ObjectNode
     */
    public final ObjectNode toObjectNode(String jsonStr) {
        JsonNode node = parse(jsonStr);
        if (node instanceof ObjectNode) {
            return (ObjectNode) node;
        }
        return null;
    }

    /**
     * 把JSON字符串转换成ArrayNode
     * @param jsonStr Json字符串
     * @return ArrayNode
     */
    public final ArrayNode toArrayNode(String jsonStr) {
        JsonNode node = parse(jsonStr);
        if (node instanceof ArrayNode) {
            return (ArrayNode) node;
        }
        return null;
    }

    public final String getString(JsonNode objectNode, String fieldName) {
        if (isExistEmpty(objectNode, fieldName)) {
            return null;
        }
        JsonNode node = objectNode.get(fieldName);
        if(node != null) {
            if (node.isBigDecimal()) {
                return node.decimalValue().toPlainString();
            }
            return node.asText();
        }
        return null;
    }

    public final Boolean getBoolean(JsonNode objectNode, String fieldName) {
        if (isExistEmpty(objectNode, fieldName)) {
            return null;
        }
        JsonNode node = objectNode.get(fieldName);
        if(node != null) {
            return node.asBoolean();
        }
        return null;
    }

    public final Double getDouble(JsonNode objectNode, String fieldName) {
        if (isExistEmpty(objectNode, fieldName)) {
            return null;
        }
        JsonNode node = objectNode.get(fieldName);
        if(node != null) {
            return node.asDouble();
        }
        return null;
    }

    public final Integer getInteger(JsonNode objectNode, String fieldName) {
        if (isExistEmpty(objectNode, fieldName)) {
            return null;
        }
        JsonNode node = objectNode.get(fieldName);
        if(node != null) {
            return node.asInt();
        }
        return null;
    }

    public final Long getLong(JsonNode objectNode, String fieldName) {
        if (isExistEmpty(objectNode, fieldName)) {
            return null;
        }
        JsonNode node = objectNode.get(fieldName);
        if(node != null) {
            return node.asLong();
        }
        return null;
    }

    public final BigDecimal getBigDecimal(JsonNode objectNode, String fieldName) {
        if (isExistEmpty(objectNode, fieldName)) {
            return null;
        }
        JsonNode node = objectNode.get(fieldName);
        if(node != null) {
            return node.decimalValue();
        }
        return null;
    }

    public final ObjectNode getObjectNode(JsonNode objectNode, String fieldName) {
        if (isExistEmpty(objectNode, fieldName)) {
            return null;
        }
        JsonNode node = objectNode.get(fieldName);
        if(node instanceof ObjectNode) {
            return (ObjectNode)node;
        }
        return null;
    }

    public final ArrayNode getArrayNode(JsonNode objectNode, String fieldName) {
        if (isExistEmpty(objectNode, fieldName)) {
            return null;
        }
        JsonNode node = objectNode.get(fieldName);
        if(node instanceof ArrayNode) {
            return (ArrayNode)node;
        }
        return null;
    }

    /**
     * 判断是否存在空值
     * @param objects 要校验的对象
     * @return boolean
     * @author lunfy
     **/
    public boolean isExistEmpty(Object... objects) {
        for (Object obj : objects) {
            if (isEmpty(obj)) {
                return true;
            }
        }
        return false;
    }
    /**
     * 判断是否存在不为空值
     * @param objects 要校验的对象
     * @return boolean
     * @author lunfy
     **/
    public boolean isExistNotEmpty(Object... objects) {
        for (Object obj : objects) {
            if (isNotEmpty(obj)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断所有参数是否都为空
     * @param objects 要校验的对象
     * @return boolean
     * @author lunfy
     **/
    public boolean isAllEmpty(Object... objects) {
        return !isExistNotEmpty(objects);
    }

    /**
     * 判断所有参数是否都不为空
     * @param objects 要校验的对象
     * @return boolean
     * @author lunfy
     **/
    public boolean isAllNotEmpty(Object... objects) {
        return !isExistEmpty(objects);
    }

    public boolean isEmpty(Object obj) {
        if (obj == null) {
            return true;
        }
        // 在Java 16及以上版本; 允许你在instanceof检查的同时，将对象解包到局部变量中
        else if (obj instanceof Optional optional) {
            return optional.isEmpty();
        }
        else if (obj instanceof CharSequence charSequence) {
            return charSequence.isEmpty();
        }
        else if (obj.getClass().isArray()) {
            return Array.getLength(obj) == 0;
        }
        else if (obj instanceof Collection collection) {
            return collection.isEmpty();
        }
        else if (obj instanceof Map map) {
            return map.isEmpty();
        }
        else {
            return false;
        }
    }
    public boolean isNotEmpty(Object obj) {
        return !isEmpty(obj);
    }

    /**
     * 转JSON字符串
     * @param obj JAVA对象
     * @param isFormat 是否格式化
     * @return String
     * @author lunfy
     **/
    private String toJsonStr(Object obj, boolean isFormat) {
        try {
            if (obj == null) {
                return "";
            }
            if (obj instanceof String) {
                return obj.toString();
            }
            if (obj instanceof Number) {
                return obj.toString();
            }
            if (isFormat) {
                return MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
            }
            return MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            log.error(String.format("toJSONString Exception: %s", obj), e);
        }
        return "";
    }

}
